/*
 * KDTree.h
 *
 *  Created on: Mar 28, 2009
 *      Author: steveca
 */

#ifndef __KDTREE_H__
#define __KDTREE_H__

#include "Prerequisite.h"
#include "SceneObject.h"

#define KD_ISLEAF(n) (n->flagAndOffset & (unsigned int)(1<<31))
#define KD_DIMENSION(n) (n->flagAndOffset & 0x3)
#define KD_OFFSET(n) (n->flagAndOffset & (0x7FFFFFFC))

namespace RTRT
{	
    // Split Planes List
    struct SplitList
    {
    	float splitPosition;
    	int n1count, n2count;
    	SplitList* next;
    };
    
	class TriangleList
	{
	public:
		TriangleList() : 
		m_trianglePtr(NULL), m_next(NULL)
		{}
		
		~TriangleList() { 
			delete m_next;
			m_next = 0;
		}
		
		void setTrianglePtr(Triangle *trianglePtr) {
			m_trianglePtr = trianglePtr;
		}
		
		Triangle *getTrianglePtr(){
			return m_trianglePtr;
		}
		
		void setNext(TrianlgeList *entry) {
			m_next = entry;
		}
		
		TriangleList *getNext() {
			return m_next;
		}
	private:
		Triangle *m_trianglePtr;
		TriangleList *m_next;
	};
	
    class KDTreeNode
    {
		typedef std::vector<SceneObject*> SceneObjArray;
    public:
        KDTreeNode() : m_flagAndOffset(6) {}
        ~KDTreeNode() {}
      
  		inline int getAxis()
        {
            // 3 = 0011
            return m_flagAndOffset & 3;
        }
        
        inline void setAxis(int axis)
        {
            // c = 1100
            m_flagAndOffset = (m_flagAndOffset & 0xfffffffc) + axis;
        }
        
        inline bool isLeafNode()
        {
            return ( (m_flagAndOffset & 4) > 0 );
        }
        
        inline void setLeaf(bool bLeaf)
        {
            // b = 1011
            // if bLeaf == true; set the bit 1
            // else set the bit 0
            m_flagAndOffset = (bLeaf)?(m_flagAndOffset|4):(m_flagAndOffset&0xfffffffb);
        }
        
        inline void setSplitPos(int splitCoordinate)
        {
            m_splitCoordinates = splitCoordinate;
        }
        
        inline int getSplitPos()
        {
            return m_splitCoordinate;
        }
        
		inline void setLeftChild(const KDTreeNode *left) {
			
		}
		
        inline KDTreeNode *getLeftChild() {
            return (KDTreeNode*)(m_flagAndOffset & 0xfffffff8);
        }
        
        inline KDTreeNode *getRightChild() {
            return ( (KDTreeNode*)(m_flagAndOffset&0xfffffff8) + 1 );
        }

		inline void addGeometry(const Triangle *tri) {
			TriangleList *entry = MemoryPool::getSingleton().newTriListEntry();
			entry->setTriPtr(tri);
			entry->setNext(getGeometryList());
		}
		
        inline TriangleList* getGeometryList() {
            return (TriangleList*)(m_flagAndOffset & 0xfffffff8);
        }

		inline void setGeometryList(TriangleList *triList) {
			m_flagAndOffset = (unsigned long)triList + (m_flagAndOffset & 7);
		}
        
    public:
        float m_splitCoordinate; 
        
        // bits 31...3 	: left child pointer (inner node) or object list pointer (leaf node)
        // bit  2		: is leaf or not
        // bits 1...0 	: split dimension
        unsigned long m_flagAndOffset;
    };
      
    /*
    class KDTree
        {
        public:
            KDTree();
            ~KDTree();
            
            KDTreeNode *getRootNode() const
            {
                return m_rootNode;
            }
            
            KDTreeNode *build();
            void insertSplitPos(float splitPos);
            void subDivide(const KTTreeNode *node, const AxisAlignedBox& AxisAlignedBox, int depth, unsigned int triCount);
            void addPrimitives(const Triangle* triangles);
            
        protected:
            // The root node of the kd-tree
            KDTreeNode *m_rootNode;
            
            // The list of tree nodes
            typedef list<KDTreeNode*> NodeList;
            NodeList m_nodeList;
            
            SplitList *m_splitList, *m_splitPool;
            
            // Pointer to the SceneManager
            SceneManager *m_sceneManager;
        };
     */
}

#endif /* KDTREE_H_ */
